<?php
/**
 * Class AliPayConfig 支付宝支付配置验证类
 */
class AliPayConfig
{
    public static $aliPayUrl = 'https://openapi.alipay.com/gateway.do?';

    CONST PAY_NAME      = 'ZFB';
    CONST SIGN_TYPE     = 'RSA';
    CONST PAY_FAILED    = 'PAY_FAILED';//支付超时
    CONST CHECK_FAILED  = 'CHECK_FAILED';//请求超时
    CONST PAY_WAIT      = 'PAY_WAIT';//等待付款
    CONST PAY_SUCCESS   = 'PAY_SUCCESS';//交易已经完成;
    //获取支付宝的相关参数

    public static function getConfig($enterpriseId='',$payType=''){
        if(empty($enterpriseId)&&empty($payType)){
            throw new Exception('参数错误,请检查企业ID,支付类型');
        }
        //获取支付配置信息
        $pay_handler = new \Biz\PayHandler();
        $pay_cls = $pay_handler->getOnlinePayConfig($enterpriseId,$payType);
        $resultTmp = array();
        if($pay_cls){
            $resultTmp['id']              = $pay_cls->getId();
            $resultTmp['enterprise_id']   = $pay_cls->getEnterpriseId();
            $resultTmp['pay_type_name']   = $pay_cls->getPayTypeName();
            $resultTmp['enterprise_name'] = $pay_cls->getEnterpriseName();
            $resultTmp['pay_config']      = unserialize($pay_cls->getPayConfig());
            $resultTmp['code']            = $pay_cls->getCode();
            $resultTmp['is_use']          = $pay_cls->getUseStatus();
            return $resultTmp;
        }
        throw new Exception('获取配置信息失败');
    }

    /**
     * 查询订单的交易状态
     * @param $orderCode
     * @param $enterpriseId
     * @return int|string 成功返回 用户下单的支付宝平台的交易号，失败返回常量值
     * @throws Exception
     */
    public static function ZFBorderQuery($orderCode,$enterpriseId){
        require_once dirname(dirname(__FILE__)).'/AliPay/MD5/lib/alipay_submit.class.php';
        require_once dirname(dirname(__FILE__)).'/AliPay/MD5/ZFBOrderQuery.php';
        $configs = self::getConfig($enterpriseId,self::PAY_NAME);
        if(!$configs){
            return 0;//支付宝配置错误
        }
        $configItems = array('partner'=>$configs['pay_config']['partner_id'],'key'=>$configs['pay_config']['key']);
        $OrderAliPay = new ZFBOrderQuery();
        $items = $OrderAliPay->getOrderQuery($orderCode,$configItems);//ok 5001000200020007151 no5001000100010001910
        //var_dump($items);exit;
        if ($items == false){
            return self::CHECK_FAILED;//sometimes return false.... //检查失败
        }
        if (array_key_exists('response',$items)){
            $trade = $items['response']['trade'];
            if ($items["is_success"]=='T'&&($trade["trade_status"]=="TRADE_FINISHED")) {
                return $trade["trade_no"];//交易成功，交易关闭不可退款
            }
            if($items["is_success"]=='T'&&($trade["trade_status"]=='TRADE_CLOSED'||$trade["trade_status"]=='TRADE_CANCEL'||$trade["trade_status"]=='TRADE_REFUSE'||$trade["trade_status"]=='TRADE_REFUSE_DEALING')) {
                return self::PAY_FAILED;//超时未支付
            }
            if($items['is_success']&&($trade['trade_status']=='WAIT_BUYER_PAY')){
                return self::PAY_WAIT;//超时未支付
            }
            if($items["is_success"]=='T'&&$trade["trade_status"]=="TRADE_SUCCESS"){
                return $trade["trade_no"];//self::PAY_SUCCESS;
            }
        }
        return self::CHECK_FAILED;
    }


/**
 * 获取签名   APP 算签名 不能排序 嗨必须 加上 值 “ ”
 * @param $data
 * @param $enterprise_private_key
 * @return bool|string
 */
    public static function getMySin($data,$enterprise_private_key){
       if(empty($data)||empty($enterprise_private_key)) throw new Exception('支付配置信息有误');
       $paraData =  self::paraFilter($data);//过滤；sin_type
       //$argData = self::argSort($paraData);
       $linkStringData = self::createLinkstring($paraData);
       $mysin = self::rsaSign($linkStringData,$enterprise_private_key);
       if($mysin){
           return urlencode($mysin);
       }
       throw new Exception('获取签名失败');

    }
    public static function getPostAlipayData($data,$sign){
        $paraData =  self::paraFilter($data);
        $para_sort = self::argSort($paraData);
        $para_sort['sign'] = $sign;
        $para_sort['sign_type'] = self::SIGN_TYPE;
        return $para_sort;
    }
/**
 * RSA签名
 * @param $data 待签名数据
 * @param $private_key 商户私钥字符串
 * return 签名结果
 */
   public static function rsaSign($data, $private_key) {
        //以下为了初始化私钥，保证在您填写私钥时不管是带格式还是不带格式都可以通过验证。
        $private_key=str_replace("-----BEGIN RSA PRIVATE KEY-----","",$private_key);
        $private_key=str_replace("-----END RSA PRIVATE KEY-----","",$private_key);
        $private_key=str_replace("\n","",$private_key);

        $private_key="-----BEGIN RSA PRIVATE KEY-----".PHP_EOL .wordwrap($private_key, 64, "\n", true). PHP_EOL."-----END RSA PRIVATE KEY-----";

        $res=openssl_get_privatekey($private_key);

        if($res)
        {
            openssl_sign($data, $sign,$res);
        }
        else {
            return false;
//            echo "您的私钥格式不正确!"."<br/>"."The format of your private_key is incorrect!";
//            exit();
        }
        openssl_free_key($res);
        //base64编码
        $sign = base64_encode($sign);
        return $sign;
    }
    /**
     * RSA验签
     * @param $data 待签名数据
     * @param $alipay_public_key 支付宝的公钥字符串
     * @param $sign 要校对的的签名结果
     * return 验证结果
     */
   public static function rsaVerify($data, $alipay_public_key, $sign)  {
        //以下为了初始化私钥，保证在您填写私钥时不管是带格式还是不带格式都可以通过验证。
        $alipay_public_key=str_replace("-----BEGIN PUBLIC KEY-----","",$alipay_public_key);
        $alipay_public_key=str_replace("-----END PUBLIC KEY-----","",$alipay_public_key);
        $alipay_public_key=str_replace("\n","",$alipay_public_key);

        $alipay_public_key='-----BEGIN PUBLIC KEY-----'.PHP_EOL.wordwrap($alipay_public_key, 64, "\n", true) .PHP_EOL.'-----END PUBLIC KEY-----';
        $res=openssl_get_publickey($alipay_public_key);
        if($res)
        {
            $result = (bool)openssl_verify($data, base64_decode($sign), $res);
        }
        else {
            echo "您的支付宝公钥格式不正确!"."<br/>"."The format of your alipay_public_key is incorrect!";
            exit();
        }
        openssl_free_key($res);
        return $result;
    }
    public static function createLinkstring($para) {
        $arg  = "";
        while (list ($key, $val) = each ($para)) {
            $arg.=$key.'="'.$val.'"&';
        }
        //去掉最后一个&字符
        $arg = substr($arg,0,count($arg)-2);
        //如果存在转义字符，那么去掉转义
        if(get_magic_quotes_gpc()){$arg = stripslashes($arg);}

        return $arg;
    }
    /**
     * 把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串，并对字符串做urlencode编码
     * @param $para 需要拼接的数组
     * return 拼接完成以后的字符串
     */
   public static function createLinkstringUrlencode($para) {
        $arg  = "";
        while (list ($key, $val) = each ($para)) {
            $arg.=$key."=".urlencode($val)."&";
        }
        //去掉最后一个&字符
        $arg = substr($arg,0,count($arg)-2);

        //如果存在转义字符，那么去掉转义
        if(get_magic_quotes_gpc()){$arg = stripslashes($arg);}

        return $arg;
    }


    /**
     * 除去数组中的空值和签名参数
     * @param $para 签名参数组
     * return 去掉空值与签名参数后的新签名参数组
     */
    private static function paraFilter($para) {
        $para_filter = array();
        while (list ($key, $val) = each ($para)) {
            if($key == "sign" || $key == "sign_type" || $val == "")continue;
            else	$para_filter[$key] = $para[$key];
        }
        return $para_filter;
    }
    /**
     * 对数组排序
     * @param $para 排序前的数组
     * return 排序后的数组
     */
   private static function argSort($para) {
        ksort($para);
        reset($para);
        return $para;
    }

   public static function getHttpResponseGET($url,$cacert_url) {
       //echo $url;exit;
        $curl = curl_init($url);
        curl_setopt($curl, CURLOPT_HEADER, 0 ); // 过滤HTTP头
        curl_setopt($curl,CURLOPT_RETURNTRANSFER, 1);// 显示输出结果
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);//SSL证书认证
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 1);//严格认证
        curl_setopt($curl, CURLOPT_CAINFO,$cacert_url);//证书地址
        $responseText = curl_exec($curl);
        //var_dump( curl_error($curl) );exit;//如果执行curl过程中出现异常，可打开此开关，以便查看异常内容
        curl_close($curl);

        return $responseText;
    }
    /**
     * 远程获取数据，POST模式
     * 注意：
     * 1.使用Crul需要修改服务器中php.ini文件的设置，找到php_curl.dll去掉前面的";"就行了
     * 2.文件夹中cacert.pem是SSL证书请保证其路径有效，目前默认路径是：getcwd().'\\cacert1.pem'
     * @param $url 指定URL完整路径地址
     * @param $cacert_url 指定当前工作目录绝对路径
     * @param $para 请求的数据
     * @param $input_charset 编码格式。默认值：空值
     * return 远程输出的数据
     */
    public static function getHttpResponsePOST($url, $cacert_url, $para, $input_charset = '') {

        if (trim($input_charset) != '') {
            $url = $url."_input_charset=".$input_charset;
        }
//        echo realpath($cacert_url);exit;
//        echo $url;
//        echo "\n";
//        print_r($para);exit;
        $curl = curl_init($url);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);//SSL证书认证
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);//严格认证
        curl_setopt($curl, CURLOPT_CAINFO,$cacert_url);//证书地址
        curl_setopt($curl, CURLOPT_HEADER, 0 ); // 过滤HTTP头
        curl_setopt($curl,CURLOPT_RETURNTRANSFER, 1);// 显示输出结果
        curl_setopt($curl,CURLOPT_POST,true); // post传输数据
        curl_setopt($curl,CURLOPT_POSTFIELDS,$para);// post传输数据
        $responseText = curl_exec($curl);
//        var_dump( curl_error($curl) );exit;//如果执行curl过程中出现异常，可打开此开关，以便查看异常内容
        curl_close($curl);
        return $responseText;
    }
}



?>